package com.sk.seckilldemo.service;

import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Service
public class OrderNoGenerator {
    // 使用Snowflake算法生成分布式ID
    private final Snowflake snowflake;

    public OrderNoGenerator(){
        // 数据中心ID和机器ID可以从配置中心获取，这里简化为1
        this.snowflake = new Snowflake(1, 1);
    }

    /**
     * 生成秒杀订单号 (格式: SK + 时间戳 + 业务编码 + 分布式ID)
     * 示例: SK20230515102030123456001
     */
    public String generateSeckillOrderNo() {
        // 1. 获取当前时间戳(格式: yyyyMMddHHmmss)
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String timestamp = LocalDateTime.now().format(formatter);

        // 2. 生成分布式序列号(12位)
        long sequence = snowflake.nextId() % 1000000000000L; // 取12位

        // 3. 组合订单号
        return String.format("SK%s%012d", timestamp, sequence);
    }

    /**
     * Snowflake算法实现(简化版)
     * */
    private static class Snowflake {
        private final long datacenterId;
        private final long machineId;
        private long sequence = 0L;
        private long lastTimestamp = -1L;

        public Snowflake(long datacenterId, long machineId) {
            this.datacenterId = datacenterId;
            this.machineId = machineId;
        }

        public synchronized long nextId() {
            long timestamp = System.currentTimeMillis();

            if (timestamp < lastTimestamp) {
                throw new RuntimeException("Clock moved backwards");
            }

            if (timestamp == lastTimestamp) {
                sequence = (sequence + 1) & 0xFFF; // 12位序列号
                if (sequence == 0) {
                    timestamp = tilNextMillis(lastTimestamp);
                }
            } else {
                sequence = 0L;
            }

            lastTimestamp = timestamp;

            return ((timestamp - 1609459200000L) << 22) // 时间戳41位
                    | (datacenterId << 17)              // 数据中心5位
                    | (machineId << 12)                 // 机器ID5位
                    | sequence;                        // 序列号12位
        }

        private long tilNextMillis(long lastTimestamp) {
            long timestamp = System.currentTimeMillis();
            while (timestamp <= lastTimestamp) {
                timestamp = System.currentTimeMillis();
            }
            return timestamp;
        }
    }
}
